package cn.richard.base.api

import android.net.ParseException
import cn.richard.base.bean.ResultData
import cn.richard.base.ext.logd
import com.google.gson.JsonParseException
import okhttp3.OkHttpClient
import org.json.JSONException
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import javax.net.ssl.SSLHandshakeException


abstract class BaseRepository {

    private val client: OkHttpClient by lazy {
        val builder = OkHttpClient.Builder()
        handleBuilder(builder)
        builder.build()
    }

    private val retrofit: Retrofit by lazy { Retrofit.Builder()
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
//                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//                .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke())
        .baseUrl(baseUrl())
        .build() }


    open fun handleBuilder(builder: OkHttpClient.Builder) {
        builder.connectTimeout(NetConstants.HTTP_REQUEST_TIMEOUT, TimeUnit.MILLISECONDS)
            .readTimeout(NetConstants.HTTP_REQUEST_TIMEOUT, TimeUnit.MILLISECONDS)
            .writeTimeout(NetConstants.HTTP_REQUEST_TIMEOUT, TimeUnit.MILLISECONDS)
    }

    protected abstract fun baseUrl():String

    /**
     * 动态配置service
     */
    fun <S> getService(serviceClass: Class<S>): S {
        return retrofit.create(serviceClass)
    }
    /**
     *  对网络请求过程中的异常进行了捕获，并返回自定义exception。
     *  @param call 实际进行网络请求 的方法 引用
     *  @param errorMessage 调用方自定义 错误信息提示，比如错误了，就提示这个消息
     *  @return KsResult ,
     */
    suspend fun <T : Any> safeApiCall(
        call: suspend () -> ResultData<T>,
        errorMessage: String? = null
    ): ResultData<T> {
        return return try {
            val result = handleException(call())
            result.toString().logd()
            result
        } catch (e: Exception) {
            // An exception was thrown when calling the API so we're converting this to an IOException
            e.printStackTrace()
            val result: ResultData<T> = handleException(e)
            result.toString().logd()
            result
        }
    }


    /**
     * 处理已经下发的异常
     */
    private fun <T> handleException(resultData: ResultData<T>): ResultData<T> {
        //可能需要根据code做额外处理
        return resultData
    }


    /**
     * 处理http过程中的异常
     */
    private fun <T>handleException(e: Exception): ResultData<T> {
        var msg = "服务器错误"
        var code = -1
        if (e is HttpException) {
            val httpException: HttpException = e as HttpException
            when (httpException.code()) {
                ERROR.UNAUTHORIZED, ERROR.FORBIDDEN, ERROR.NOT_FOUND, ERROR.REQUEST_TIMEOUT,
                ERROR.GATEWAY_TIMEOUT, ERROR.INTERNAL_SERVER_ERROR, ERROR.BAD_GATEWAY, ERROR.SERVICE_UNAVAILABLE ->{
                    msg = "网络错误"
                    code = httpException.code()
                }else -> {
                    msg = "未知网络错误"
                    code = -1
                }
            }
        } else if (e is JsonParseException
            || e is JSONException
            || e is ParseException
        ) {
            code = ERROR.PARSE_ERROR
            msg = "解析错误"
        } else if (e is ConnectException) {
            code = ERROR.NETWORD_ERROR
            msg = "连接失败"
        } else if (e is SSLHandshakeException) {
            code = ERROR.SSL_ERROR
            msg = "证书验证失败"
        } else if (e is TimeoutException) {
            code = ERROR.TIMEOUT_ERROR
            msg = "连接超时"
        } else if (e is SocketTimeoutException) {
            code = ERROR.TIMEOUT_ERROR
            msg = "连接超时"
        } else if (e is UnknownHostException) {
            code = ERROR.CONNECT_ERROR
            msg = "网络故障，无法连接"
        } else {
            code = ERROR.UNKNOWN
            msg = "未知错误"
        }
        return ResultData(code, msg, null)
    }


    /**
     * 约定异常
     */
    internal object ERROR {
        const val UNAUTHORIZED = 401
        const val FORBIDDEN = 403
        const val NOT_FOUND = 404
        const val REQUEST_TIMEOUT = 408
        const val INTERNAL_SERVER_ERROR = 500
        const val BAD_GATEWAY = 502
        const val SERVICE_UNAVAILABLE = 503
        const val GATEWAY_TIMEOUT = 504

        /**
         * 未知错误
         */
        const val UNKNOWN = 1000
        /**
         * 解析错误
         */
        const val PARSE_ERROR = 1001
        /**
         * 网络错误
         */
        const val NETWORD_ERROR = 1002
        /**
         * 协议出错
         */
        const val HTTP_ERROR = 1003
        /**
         * 证书出错
         */
        const val SSL_ERROR = 1005
        /**
         * 连接超时
         */
        const val TIMEOUT_ERROR = 1006
        /**
         * 连接服务器失败
         */
        const val CONNECT_ERROR = 1007
    }
}